﻿using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.IO;
using System.Security.Principal;
using System.Diagnostics;

namespace SourceBackup
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        public MainForm(string startupPath) 
        {
            InitializeComponent();
            this.startupPath = startupPath.Trim('"');            
        }

        private string startupPath = "";
        private DirBackup myDirBackup;

        #region Form events
        private void MainForm_Load(object sender, EventArgs e)
        {
            restartInAdminModeToolStripMenuItem.Visible = !AdminModeTools.IsAdmin();
            pictureBoxShield.Visible = AdminModeTools.IsAdmin();
            if (Properties.Settings.Default.MainFormSize != new Size(0, 0))
            {
                this.Location = Properties.Settings.Default.MainFormLocation;
                this.Size = Properties.Settings.Default.MainFormSize;
            }
            else
            {
                this.Location = new Point((Screen.PrimaryScreen.WorkingArea.Width - this.Width) / 2, (Screen.PrimaryScreen.WorkingArea.Height - this.Height) / 2);
            }
            
            
            this.Text += " - " + Application.ProductVersion;
            
            //DelayExecute.Execute(this, 500, (MethodInvoker)LoadFilters);
        }
        private void MainForm_Shown(object sender, EventArgs e)
        {
            cboRoot.Text = Properties.Settings.Default.LastRoot;

            if (Properties.Settings.Default.PrevRoots == null)
                Properties.Settings.Default.PrevRoots = new System.Collections.Specialized.StringCollection();
            foreach (string prevRoot in Properties.Settings.Default.PrevRoots)
            {
                if (prevRoot.Length != 0)
                {
                    cboRoot.Items.Add(prevRoot);
                }
            }
            LoadFilters();
            if (startupPath.Length > 0 && startupPath.EndsWith(".sbkd"))
            {
                LoadSourceBackupFile(startupPath);
            }
            else 
            {
                if (startupPath.Length > 0)
                    cboRoot.Text = startupPath;
                if (cboRoot.Text.EndsWith("\\"))
                    cboRoot.Text = cboRoot.Text.Substring(0, cboRoot.Text.Length - 1);
                chkAppendDate.Checked = Properties.Settings.Default.AppendDate;
                chkAppendTime.Checked = Properties.Settings.Default.AppendTime;
                chkShowIgnored.Checked = Properties.Settings.Default.ShowIgnoredFiles;
                chkIgnoreBinObj.Checked = Properties.Settings.Default.IgnoreBinObjDirs;
                optNone.Checked = (Properties.Settings.Default.LastAfterwardsAction == 0);
                optCopy.Checked = (Properties.Settings.Default.LastAfterwardsAction == 1);
                optMove.Checked = (Properties.Settings.Default.LastAfterwardsAction == 2);
            }
        }
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (WindowState == FormWindowState.Normal)
            {
                Properties.Settings.Default.MainFormLocation = this.Location;
                Properties.Settings.Default.MainFormSize = this.Size;
            }
            if (cboFilter.SelectedItem != null)
            {
                Properties.Settings.Default.LastBackupFilterName = ((BackupFilter)cboFilter.SelectedItem).Name;
            }
            if (optNone.Checked)
                Properties.Settings.Default.LastAfterwardsAction = 0;
            else if (optCopy.Checked)
                Properties.Settings.Default.LastAfterwardsAction = 1;
            else if (optMove.Checked)
                Properties.Settings.Default.LastAfterwardsAction = 2;
            Properties.Settings.Default.AppendDate = chkAppendDate.Checked;
            Properties.Settings.Default.AppendTime = chkAppendTime.Checked;
            Properties.Settings.Default.ShowIgnoredFiles = chkShowIgnored.Checked;
            Properties.Settings.Default.IgnoreBinObjDirs = chkIgnoreBinObj.Checked;
            Properties.Settings.Default.LastRoot = cboRoot.Text;
            Properties.Settings.Default.LastRun = DateTime.Now;
            Properties.Settings.Default.Save();
        } 
        #endregion

        #region menu events
        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog openSourceBackupFile = new OpenFileDialog();
            openSourceBackupFile.Filter = "Source backup definition|*.sbkd";
            openSourceBackupFile.DefaultExt = "sbkd";
            openSourceBackupFile.Title = "Open source backup definition";
            if (openSourceBackupFile.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                LoadSourceBackupFile(openSourceBackupFile.FileName);
            }
        }
        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveSourceBackupFile = new SaveFileDialog();
            saveSourceBackupFile.Filter = "Source backup definition|*.sbkd";
            saveSourceBackupFile.DefaultExt = "sbkd";
            saveSourceBackupFile.Title = "Save source backup definition";
            if (saveSourceBackupFile.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                SaveSourceBackupFile(saveSourceBackupFile.FileName);
            }
        }
        private void restartInAdminModeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AdminModeTools.RestartInAdminMode(false);
        }
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }
        private void filtersToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MaintainFilters maintainFilters = new MaintainFilters();
            maintainFilters.ShowDialog();
            LoadFilters();
        }
        private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (OptionsWindow optionsWindow = new OptionsWindow())
            {
                optionsWindow.ShowDialog();
            }
        }
        #endregion

        #region Checkbox events
        private void cboRoot_SelectedIndexChanged(object sender, EventArgs e)
        {
            txtZipFile.Text = SetZipFileName();
        }
        private void chkAppendDate_CheckedChanged(object sender, EventArgs e)
        {
            txtZipFile.Text = SetZipFileName();
        } 
        #endregion

        #region Extra utils
        private void LoadFilters()
        {
            if (cboFilter.SelectedItem != null)
            {
                Properties.Settings.Default.LastBackupFilterName = ((BackupFilter)cboFilter.SelectedItem).Name;
            }
            cboFilter.Items.Clear();
            foreach (string backupFilterSerialized in Properties.Settings.Default.BackupFilters)
            {
                BackupFilter backupFilter = SerializationUtils.DeserializeXML<BackupFilter>(backupFilterSerialized);
                cboFilter.Items.Add(backupFilter);
                if (Properties.Settings.Default.LastBackupFilterName == backupFilter.Name)
                    cboFilter.SelectedItem = backupFilter;
            }
            if (cboFilter.SelectedItem != null)
            {
                Properties.Settings.Default.LastBackupFilterName = ((BackupFilter)cboFilter.SelectedItem).Name;
            }
            else if (cboFilter.Items.Count > 0)
            {
                cboFilter.SelectedIndex = 0;
                Properties.Settings.Default.LastBackupFilterName = cboFilter.Text;
            }
        }
        private string SetZipFileName()
        {
            string zipName = "";
            zipName = cboRoot.Text.Substring(cboRoot.Text.LastIndexOf("\\") + 1);
            if (zipName.Length > 0)
            {
                if (chkAppendDate.Checked)
                {
                    zipName += "-" + DateTime.Now.ToString("yyyy-MM-dd");
                }
                if (chkAppendTime.Checked)
                {
                    zipName += "-" + DateTime.Now.ToString("HH-mm-ss");
                }
                zipName = cboRoot.Text + @"\" + zipName + ".zip";
            }
            return zipName;
        }
        private void AddPrevRoot(string root)
        {
            if (!Properties.Settings.Default.PrevRoots.Contains(root))
            {
                Properties.Settings.Default.PrevRoots.Add(root);
                Properties.Settings.Default.Save();
                cboRoot.Items.Add(root);
            }
        }
        #endregion

        #region RTF output
        private void WriteOutput(string message)
        {
            WriteLine(message, SystemColors.WindowText);
        }
        private void WriteOutputBlue(string message)
        {
            WriteLine(message, Color.Blue);
        }
        private void WriteOutputBold(string message)
        {
            WriteLineBold(message, SystemColors.WindowText);
        }
        private void WriteOutputNoCRLF(string message)
        {
            Write(message, SystemColors.WindowText);
        }
        private void WriteWarning(string message)
        {
            WriteLine(message, Color.Red);
        }
        private void WriteLine(string text, Color textColor)
        {
            AddFormatRTFLine(text, FontStyle.Regular, 8, textColor);
        }
        private void WriteLineBold(string text, Color textColor)
        {
            AddFormatRTFLine(text, FontStyle.Bold, 8, textColor);
        }
        private void Write(string text, Color textColor)
        {
            AddFormatRTFLine(text, FontStyle.Regular, 8, textColor, false);
        }
        private void WriteBold(string text, Color textColor)
        {
            AddFormatRTFLine(text, FontStyle.Bold, 8, textColor, false);
        }
        private void AddFormatRTFLine(string text, FontStyle fs, float fontsize, Color textColor)
        {
            AddFormatRTFLine(text, fs, fontsize, textColor, true);
        }
        private void AddFormatRTFLine(string text, FontStyle fs, float fontsize, Color textColor, bool crlf)
        {
            if (text.Length > 0)
            {
                int startpos = rtxtOutput.TextLength;
                rtxtOutput.AppendText(text);
                int endpos = rtxtOutput.TextLength;

                rtxtOutput.SelectionStart = startpos;
                rtxtOutput.SelectionLength = endpos - startpos;
                rtxtOutput.SelectionFont = new Font("Microsoft Sans Serif", fontsize, fs);
                rtxtOutput.SelectionColor = textColor;
            }
            if (crlf)
                rtxtOutput.AppendText("\r\n");
            rtxtOutput.ScrollToCaret();
            Application.DoEvents();
        } 
        #endregion

        #region Buttons events
        private void cmdBrowseRoot_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog dbd = new FolderBrowserDialog();
            if (cboRoot.Text.Length > 0)
            {
                dbd.SelectedPath = cboRoot.Text;
            }
            if (dbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                cboRoot.Text = dbd.SelectedPath;
                txtZipFile.Text = SetZipFileName();
            }
        }
        private void cmdSetZip_Click(object sender, EventArgs e)
        {
            dlg.FileName = txtZipFile.Text;
            if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                txtZipFile.Text = dlg.FileName;
            }
        }
        private void cmdDoBackup_Click(object sender, EventArgs e)
        {
            try
            {
                if (cboRoot.Text.EndsWith("\\"))
                    cboRoot.Text = cboRoot.Text.Substring(0, cboRoot.Text.Length - 1);

                if (txtZipFile.Text.Length == 0)
                {
                    txtZipFile.Text = SetZipFileName();
                }
                if (txtZipFile.Text.Length > cboRoot.Text.Length)
                {
                    if (txtZipFile.Text.Substring(0, cboRoot.Text.Length) != cboRoot.Text)
                    { if (MessageBox.Show("Zip file not in source directory! Continue?", "Continue", MessageBoxButtons.YesNo) == DialogResult.No) { return; } }
                }
                if (cboFilter.SelectedItem == null)
                {
                    MessageBox.Show("You must specify a filter!", "Filter", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                }
                else if (cboRoot.Text.Length > 0 && txtZipFile.Text.Length > 0)
                {
                    BackupFilter backupFilter = (BackupFilter)cboFilter.SelectedItem;
                    if (File.Exists(txtZipFile.Text)) { File.Delete(txtZipFile.Text); }
                    rtxtOutput.Text = "";

                    Application.DoEvents();
                    myDirBackup = new DirBackup();
                    myDirBackup.ShowIgnoredFiles = chkShowIgnored.Checked;
                    myDirBackup.IgnoreBinObjDirs = chkIgnoreBinObj.Checked;
                    myDirBackup.FileFilters.AddRange(
                        (from string s in backupFilter.FilterList
                         select s).ToArray<string>());
                    myDirBackup.Feedback += new DBackupFeedback(WriteOutput);
                    myDirBackup.FeedbackBold += new DBackupFeedback(WriteOutputBlue);
                    myDirBackup.FeedbackNoRCLF += new DBackupFeedback(WriteOutputNoCRLF);
                    myDirBackup.FeedbackWarning += new DBackupFeedback(WriteWarning);
                    Cursor.Current = Cursors.WaitCursor;
                    myDirBackup.DoBackup(txtZipFile.Text, cboRoot.Text);

                    WriteOutputBold("-------------------------------------------");
                    WriteOutputBold("Total number of files processed: " + myDirBackup.FilesZipped.ToString());
                    WriteOutputBold("Total size uncompressed (KB): " + myDirBackup.TotalUncompressedSizeKB.ToString());
                    WriteOutputBold("Total size compressed (KB): " + myDirBackup.TotalCompressedSizeKB.ToString());
                    WriteOutputBold("-------------------------------------------");
                    if (myDirBackup.ExcludedFileTypes.Count > 0)
                    {
                        WriteWarning("File extensions ignored");
                        string extnsIgnored = "";
                        foreach (string extnIgnored in (from s in myDirBackup.ExcludedFileTypes
                                                        orderby s
                                                        select s))
                        {
                            extnsIgnored += "*" + extnIgnored + "; ";
                        }
                        WriteWarning(extnsIgnored);
                    }

                    AddPrevRoot(cboRoot.Text);

                    if (optCopy.Checked || optMove.Checked)
                    {
                        WriteOutputBold("Afterwards action");
                        if (optCopy.Checked)
                        {
                            if (System.IO.File.Exists(txtZipFile.Text))
                            {
                                dlgsave.FileName = Path.GetFileName(txtZipFile.Text);
                                if (dlgsave.ShowDialog() == DialogResult.OK)
                                {
                                    Cursor.Current = Cursors.WaitCursor;
                                    File.Copy(txtZipFile.Text, dlgsave.FileName, true);
                                    WriteOutput(string.Format("  Copied '{0}' to '{1}'", txtZipFile.Text, dlgsave.FileName));
                                }
                                else
                                    WriteOutput("  Cancelled");
                            }
                        }
                        else if (optMove.Checked)
                        {
                            if (System.IO.File.Exists(txtZipFile.Text))
                            {
                                dlgsave.InitialDirectory = Properties.Settings.Default.LastMoveToDir;
                                dlgsave.FileName = Path.GetFileName(txtZipFile.Text);
                                dlgsave.Title = "Move zip file";
                                if (dlgsave.ShowDialog() == DialogResult.OK)
                                {
                                    Cursor.Current = Cursors.WaitCursor;
                                    try
                                    {
                                        if (File.Exists(dlgsave.FileName))
                                        {
                                            File.SetAttributes(dlgsave.FileName, FileAttributes.Normal);
                                            File.Delete(dlgsave.FileName);
                                        }

                                        File.Move(txtZipFile.Text, dlgsave.FileName);
                                        WriteOutput(string.Format("  Moved '{0}' to '{1}'", txtZipFile.Text, dlgsave.FileName));
                                        Properties.Settings.Default.LastMoveToDir = Path.GetDirectoryName(dlgsave.FileName);
                                    }
                                    catch (UnauthorizedAccessException)
                                    {
                                        WriteWarning("  Needs Administrative access");
                                        MoveFile(txtZipFile.Text, dlgsave.FileName);
                                        WriteOutput(string.Format("  Moved '{0}' to '{1}'", txtZipFile.Text, dlgsave.FileName));
                                    }
                                }
                                else
                                    WriteOutput("  Cancelled");
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                Cursor.Current = Cursors.Default;
            }
        }

        private void MoveFile(string sourceFile, string destinationFile)
        {
            System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
            startInfo.UseShellExecute = true;
            startInfo.WorkingDirectory = Environment.CurrentDirectory;
            startInfo.FileName = Application.ExecutablePath; 
            startInfo.Arguments = string.Format("-m \"{0}\" \"{1}\" ", sourceFile, destinationFile);
            startInfo.Verb = "runas";
            try
            {
                System.Diagnostics.Process p = System.Diagnostics.Process.Start(startInfo);
            }
            catch (System.ComponentModel.Win32Exception)
            {
                return;
            }
        }
        #endregion

        #region Source backup definition
        public void LoadSourceBackupFile(string filePath)
        {
            try
            {
                SourceBackupFile sourceBackupFile = SerializationUtils.DeserializeXMLFile<SourceBackupFile>(filePath);
                cboFilter.Text = sourceBackupFile.FilterName;
                cboRoot.Text = sourceBackupFile.SolutionFolder;
                chkAppendDate.Checked = sourceBackupFile.AppendDate;
                chkShowIgnored.Checked = sourceBackupFile.ShowIgnoredFiles;
                chkIgnoreBinObj.Checked = sourceBackupFile.IgnoreBinObj;
                if (sourceBackupFile.ZipFilePath.Length > 0)
                    txtZipFile.Text = sourceBackupFile.ZipFilePath;
                optNone.Checked = true;
                optCopy.Checked = sourceBackupFile.PostBackupAction.ToLower() == "copy";
                optMove.Checked = sourceBackupFile.PostBackupAction.ToLower() == "move";
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Open source backup definition", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        public void SaveSourceBackupFile(string filePath)
        {
            try
            {
                SourceBackupFile sourceBackupFile = new SourceBackupFile();
                sourceBackupFile.SolutionFolder = cboRoot.Text;
                sourceBackupFile.ZipFilePath = txtZipFile.Text;
                sourceBackupFile.FilterName = cboFilter.Text;
                sourceBackupFile.AppendDate = chkAppendDate.Checked;
                sourceBackupFile.ShowIgnoredFiles = chkShowIgnored.Checked;
                sourceBackupFile.IgnoreBinObj = chkIgnoreBinObj.Checked;
                sourceBackupFile.PostBackupAction = optNone.Checked ? "none" : optCopy.Checked ? "copy" : optMove.Checked ? "move" : "none";
                sourceBackupFile.SaveToFile(filePath);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Save source backup definition", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        #endregion        

    }
}
